<template>
  <div class="app-container">
    <el-container>
      <el-container class="main-create">
        <el-main class="left-create hide-scrollbar">
          <!-- 应用需求描述部分 -->
          <div v-if="appRequirement !== ''" class="app-requirement">
            <p>
              <span style="font-weight: bold">{{ $t('appRequirement') }}：</span>
              {{ appRequirement }}
            </p>
          </div>
          <!-- 等待规划进度条 -->
          <div
            v-if="waitingTaskList"
            v-loading="waitingTaskList"
            :element-loading-text="$t('appPlanning')"
            element-loading-spinner="el-icon-loading"
            class="waiting-task-list sub-task"
          >
            <div style="padding-top:30px; padding-bottom: 30px;" />
          </div>
          <!-- 子任务规划部分 -->
          <div v-for="(item, key) in taskList" :key="'taskList' + key" class="sub-task">
            <!-- 子任务展示部分 选择好工具的展示详情 反之仅展示概述 -->
            <task-create
              :ref="'create'+key"
              v-model="item.task"
              :task_id="key+1"
              :array_key="key"
              :show_edit="item.show_edit"
              @auto_choose="autoChooseTask"
              @manual_choose="manualChooseTools"
              @change_show_edit="showTaskEdit"
              @insert_sub_task="insertSubTask"
              @delete_sub_task="deleteSubTask"
            />
            <div v-if="'tool_id' in item" v-show="item.show_edit">
              <task-edit
                :ref="'task'+key"
                :sub_task_args="item.parameters"
                :tool_id="item.tool_id"
                :tool_name="item.tool_name"
                :task_id="key+1"
                :old_front_code="item.pre_code"
                :old_end_code="item.post_code"
                @refresh_memory_bus="generateMemoryBus"
              />
            </div>
          </div>
          <el-row v-show="taskList.length > 0" type="flex" align="middle" :gutter="6" class="save-button-container">
            <el-col :span="2.5">
              <el-button type="primary" class="sava-button" @click="toRun"> {{ $t('running') + $t('application') }} </el-button>
            </el-col>
            <el-col :span="2.5">
              <el-button type="common" class="sava-button" @click="confirmSaveAsApp"> {{ $t('appSave') }} </el-button>
            </el-col>
            <el-col :span="2.5">
              <el-button type="common" class="sava-button" @click="saveAndShowAppScript"> {{ $t('check') + $t('script') }} </el-button>
            </el-col>
            <el-col :span="2.5">
              <el-button type="common" class="sava-button" @click="toDetail"> {{ $t('back_to_detail') }} </el-button>
            </el-col>
          </el-row>
          <!-- 反思按钮，暂时不用
          <el-button v-if="judgeNextOrSave" class="save-button" type="danger" @click="reflectProb">{{ $t('reflect') }}</el-button>-->
          <div v-if="showInput" class="input-create">
            <chat-input @confirm_send="confirmSend" />
          </div>
        </el-main>
      </el-container>
    </el-container>
    <!-- 反馈的对话框 -->
    <el-dialog title="reflectWindows" center :visible.sync="reflectDialogVisible">
      <!-- 选择错误的类型 -->
      <el-select v-model="errorType" :placeholder="$t('wrong_type_rule')">
        <el-option label="Workflow design error" value="Workflow design error" />
        <el-option label="Task dependency ignore error" value="Task dependency ignore error" />
        <el-option label="Tool's arguments error" value="Tool's arguments error" />
        <el-option label="Methodology use error" value="Methodology use error" />
      </el-select>
      <!-- 用户输入对本次错误的描述 -->
      <el-input v-model="reflectMessage" :placeholder="$t('error_description_tips')" />
      <!-- runningLogs的内容 -->
      <!-- 一个提交按钮 -->
      <el-button @click="submitReflect">{{ $t('Confirm_submission') }}</el-button>
    </el-dialog>
    <!-- 要求用户输入app的名称和描述的弹窗 -->
    <el-dialog :visible.sync="saveAsAppVisible" :title="$t('app_new_name_description_rule')">
      <el-input v-model="describeAppName" :placeholder="$t('app_new_name_rule')" style="margin-bottom: 10px" />
      <el-input v-model="describeApp" :autosize="{ minRows: 5, maxRows: 10 }" type="textarea" :placeholder="$t('app_new_description_rule')" style="margin-top: 10px;" />
      <span slot="footer" class="dialog-footer">
        <!-- <a href="#" class="llm-link" @click="llmRecommended">智能推荐应用名称和描述</a> -->
        <el-button @click="saveAsAppVisible = false; describeAppName = ''; describeApp = '';">{{ $t('cancel') }}</el-button>
        <el-button type="primary" @click="submitSavaAsApp">{{ $t('confirm') }}</el-button>
      </span>
    </el-dialog>
    <!-- 展示应用脚本 -->
    <el-dialog :visible.sync="showAppScript" :title="$t('application') + $t('script')">
      <el-form label-width="80px">
        <json_code v-model="appScript" />
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="SaveAppScript">{{ $t('apply_changes') }}</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import chatInput from '@/components/AppCreate/chat/chatInput.vue'
import { retrieveTools } from '@/api/tool'
import taskEdit from '@/components/AppCreate/task/taskEdit.vue'
import JsonCodeMirror from '@/components/JavascriptCodemirror/index.vue'
import taskCreate from '@/components/AppCreate/task/subtaskGenerator.vue'
import MemoryBus from '@/components/AppCreate/task/memoryBus'
import { reflectWorkflow, createWorkflow, saveWorkflowAsApp, generateAppInfo, getAppDetail, updateApp } from '@/api/app'

export default {
  components: {
    json_code: JsonCodeMirror,
    chatInput,
    taskEdit,
    taskCreate
  },
  data() {
    return {
      /* 应用创建需求输入部分 */
      inputData: '',
      showInput: true,
      /* 应用需求存储部分 */
      appRequirement: '',
      waitingTaskList: false, // 是否在等待任务列表生成
      /* 应用创建阶段前端维护的MemoryBus */
      memoryBus: new MemoryBus(this.$store.getters.id),
      /* */
      front_code: 'def before_task(memory_bus,logger,process_control):\n' +
        '    return',
      end_code: 'def after_task(memory_bus,logger,process_control):\n' +
        '    return',
      /* 子任务规划部分 */
      taskList: [], // task相关的列表，用于用户自定task的arg
      task_id: 0,
      args: [],
      waitingSubtaskPlanning: false, // 是否在等待子任务的规划
      /* chat的存储部分 */
      tool: '',
      appID: -1,
      errorType: '',
      reflectMessage: '',
      /* 保存为应用相关 */
      isSavedAsApp: false,
      saveAsAppVisible: false,
      describeAppName: '',
      describeApp: '',
      dialogVisible: false,
      reflectDialogVisible: false,
      app_no_authentication_access: false,
      api_model_enable: false,
      api_model_description: '',
      creator_id: '',
      // 应用是否被首次保存过
      saved: false,
      /* 编辑相关 */
      isEdit: false,
      gotRef: false,
      /* 应用脚本相关 */
      appScript: '',
      showAppScript: false
    }
  },
  created() {
    // 从query请求中获取App id
    this.appID = this.$route.query.id
    // 根据传入的参数判断是新建还是编辑
    if (this.appID === -1) {
      // console.log('新建页面，确实新建')
    } else if (this.appID === -2) {
      // console.log('新建页面，创建空应用')
      this.confirmSend('创建一个空任务的应用')
    } else {
      // console.log('新建页面，实现编辑')
      this.saved = true
      this.isEdit = true
      this.showInput = false // 关闭需求输入框
      // 从后端获取详细的应用详情JSON
      getAppDetail(this.appID).then(async res => {
        // this.appDetail = res
        const app_detail = res
        // console.log('编辑页面，获取到的应用详情', this.appDetail)
        // 填入应用需求等应用基本信息
        this.appRequirement = app_detail.app_requirement
        this.describeAppName = app_detail.app_name
        this.describeApp = app_detail.app_description
        this.app_no_authentication_access = app_detail.app_no_authentication_access
        this.api_model_enable = app_detail.api_model_enable
        this.api_model_description = app_detail.api_model_description
        this.creator_id = app_detail.creator_id
        // 解析出taskList
        this.taskList = JSON.parse(app_detail.script)
        // 刷新 memoryBus
        this.$nextTick(() => {
          this.generateMemoryBus()
        })
      }).catch(err => {
        console.log('应用编辑页面，获取应用详情出错', err)
      })
    }
  },
  methods: {
    // 发送创建workflow的请求
    confirmSend(data) {
      // 隐藏输入框
      this.showInput = false
      // 添加用户的自然语言信息
      this.inputData = data
      this.appRequirement = data // 添加用户需求
      let instruction = {
        'instruction': this.inputData
      }
      instruction = JSON.stringify(instruction)
      this.inputData = ''
      // 设置为等待响应结果
      if (data !== '创建一个空任务的应用') {
        this.waitingTaskList = true
      }
      this.task_id = 0
      // console.log(instruction)
      createWorkflow(instruction).then(response => {
        // 取task列表并一个个展示args，供用户修改
        this.taskList = response.tasks
        console.log('获取到的子任务列表:', this.taskList)

        // 获取了taskList后，生成初始的 memoryBus
        this.generateMemoryBus()
        this.waitingTaskList = false
      }).catch(error => {
        console.log(error)
        this.$message({
          message: this.$t('create_error_tips'),
          type: 'error'
        })
        // /todo 创建失败后，清空需求
        this.waitingTaskList = false
      })
    },
    // 发送保存为App的请求
    async confirmSaveAsApp() {
      if (this.isEdit) {
        await this.submitSavaAsApp()
      } else {
        // 弹出输入workflow保存信息的dialog
        this.saveAsAppVisible = true

        // 默认将应用名称和应用描述填写为用户的原始请求
        // this.describeAppName = this.appRequirement
        // this.describeApp = this.appRequirement
      }
    },
    submitReflect() {
      // 发送反馈信息
      const reflect = {
        'error_type': this.errorType,
        'reflection': this.reflectMessage,
        'instruction': this.runningLogs[this.task_id].instruction
      }
      reflectWorkflow(reflect).then(response => {
        /* this.$message({
          message: '反馈成功',
          type: 'success'
        }) */
      }).catch(error => {
        console.log(error)
        this.$message({
          message: this.$t('Feedback_failure'),
          type: 'error'
        })
      })
      // 关闭对话框      this.reflectDialogVisible = false
    },
    // 生成最新的 taskList
    async generateTaskList() {
      // 挂载上了，生成 taskList
      const taskList = []
      // 获取每一个子任务的有关数据
      for (const key in this.taskList) {
        let task
        if ('tool_id' in this.taskList[key] && this.$refs['task' + key]) {
          // 选择了工具，则获取详情信息
          task = this.$refs['task' + key][0].getTaskInfo()
          task['task'] = this.taskList[key].task
        } else {
          // 否则，只填入默认信息
          task = {
            'task': this.taskList[key].task,
            'task_id': this.taskList[key].task_id
          }
        }
        taskList.push(task)
      }
      return taskList
    },
    async saveAndShowAppScript() {
      // 应用脚本不需要保存到后端即可查看
      // 保存并显示应用脚本
      const script = await this.generateTaskList()
      this.appScript = JSON.stringify(script, null, 2)
      this.showAppScript = true
    },
    SaveAppScript() {
      // 只更新应用脚本
      this.taskList = JSON.parse(this.appScript, null, 2)
      this.showAppScript = false
      // 刷新一遍 memoryBus
      this.$nextTick(() => {
        this.generateMemoryBus()
      })
    },
    async toRun() {
      // 若不是编辑且未首次保存，先保存
      if (!this.saved) {
        await this.confirmSaveAsApp()
      } else {
        // 跳转到运行页面
        this.$router.push({ path: `/app_management/index/details/chatExecutingUser`, query: { id: this.appID }})
      }
    },
    async toDetail() {
      if (!this.saved) {
        await this.confirmSaveAsApp()
      } else {
        // 跳转到详情页面
        this.$router.push({ path: '/app_management/index/details/', query: { id: this.appID }})
      }
    },
    async submitSavaAsApp() {
      // 关闭对话框
      this.saveAsAppVisible = false
      // 初始化应用脚本
      const appScript = await this.generateTaskList()
      const app = {
        'app_requirement': this.appRequirement,
        'app_name': this.describeAppName,
        'app_description': this.describeApp,
        'app_no_authentication_access': this.app_no_authentication_access,
        'api_model_enable': this.api_model_enable,
        'api_model_description': this.api_model_description,
        'creator_id': this.creator_id ? this.creator_id : this.$store.getters.id,
        'script': [...appScript]
      }
      console.log('保存的App内容:', app)
      /* 发送到后端 */
      // 若为编辑或已经首次保存过，则更新应用
      if (this.isEdit || this.saved) {
        app['id'] = parseInt(this.appID)
        await updateApp(app).then(res => {
          console.log('修改应用成功', res)
          // 保存成功后仅提示保存成功
          this.$message.success(this.$t('save_success'))
        }).catch(err => {
          console.log('确认修改应用失败', err)
        })
      } else {
        await saveWorkflowAsApp(app).then(response => {
          console.log('保存App后的响应:', response)
          // 关闭保存按钮
          this.isSavedAsApp = true
          // 保存成功后仅提示保存成功，并存储 appID
          this.appID = response.inserted_id
          this.$message.success(this.$t('save_success'))
        }).catch(error => {
          console.log('保存App内容时错误', error)
          // 保存失败
          this.$message({
            message: this.$t('save_failure'),
            type: 'error'
          })
        })
      }
      // 标记已首次保存
      this.saved = true
    },
    // 更改详情的展示与否
    showTaskEdit(index) {
      // console.log('下拉框变更', index)
      this.taskList[index]['show_edit'] = !this.taskList[index]['show_edit']
      this.$forceUpdate()
    },
    // 将数据填入taskList中
    chooseTool(row, index) {
      // 添加参数
      this.taskList[index]['parameters'] = row.parameters
      // 添加 tool_id
      this.taskList[index]['tool_id'] = row.id
      // 添加是否展示详情的属性
      this.taskList[index]['show_edit'] = false
      console.log('装填工具后的子任务', this.taskList[index])
      // 添加前置、后置代码
      this.taskList[index]['pre_code'] = this.front_code
      this.taskList[index]['post_code'] = this.end_code
      // 替换原工具时，清空组件中可能已经选好的部分
      if (this.$refs['task' + index] && this.$refs['task' + index][0]) {
        this.$refs['task' + index][0].clearTaskArgs()
      }
      // 取消加载条
      this.$refs['create' + index][0].loadComplete()
      // 刷新 memory bus
      this.generateMemoryBus()
    },
    // 手动选择
    manualChooseTools(row, index) {
      const tempData = JSON.parse(row)
      // 如果原本已经选择了工具，弹出确认框
      if ('tool_id' in this.taskList[index]) {
        // console.log('已经选择工具')
        this.$confirm(this.$t('reselect_tool'), this.$t('warning'), {
          confirmButtonText: this.$t('confirm'),
          cancelButtonText: this.$t('cancel'),
          type: 'warning',
          closeOnClickModal: false
        }).then(() => {
          // 填入手动选择好的工具
          this.chooseTool(tempData, index)
        }).catch(() => {
          // 取消加载条
          this.$refs['create' + index][0].loadComplete()
        })
      } else {
        // 填入手动选择好的工具
        this.chooseTool(tempData, index)
      }
    },
    // 自动选择任务
    autoChooseTask(index) {
      if ('tool_id' in this.taskList[index]) {
        // console.log('已经选择工具')
        this.$confirm(this.$t('reselect_tool'), this.$t('warning'), {
          confirmButtonText: this.$t('confirm'),
          cancelButtonText: this.$t('cancel'),
          type: 'warning',
          closeOnClickModal: false
        }).then(() => {
          const data = {
            'instruction': this.taskList[index].task,
            'topk': 1
          }
          retrieveTools({ 0: data }).then(response => {
            // 填入智能选择好的工具
            this.chooseTool(response[0], index)
          }).catch(error => {
            console.log('智能选择参数失败：', error)
          })
        }).catch(() => {
          // 取消加载条
          this.$refs['create' + index][0].loadComplete()
        })
      } else {
        const data = {
          'instruction': this.taskList[index].task,
          'topk': 1
        }
        retrieveTools({ 0: data }).then(response => {
          // 填入智能选择好的工具
          this.chooseTool(response[0], index)
          // console.log('获取到的工具', response)
        }).catch(error => {
          console.log('智能选择参数失败：', error)
        })
      }
    },
    // 插入一个子任务
    async insertSubTask(index, content) {
      // 插入操作前，需要先保存 taskList
      this.taskList = await this.generateTaskList()
      // 进行插入操作
      this.taskList.splice(index, 0, { 'task': content, 'show_edit': false })
      // console.log('添加了一个子任务', this.taskList)
      // 刷新 MemoryBus
      this.$nextTick(() => {
        this.generateMemoryBus()
      })
    },
    // 删除一个子任务
    async deleteSubTask(index) {
      // 删除操作前，需要先保存 taskList
      this.taskList = await this.generateTaskList()
      // 进行删除操作
      this.taskList.splice(index, 1)
      // 刷新 MemoryBus
      this.$nextTick(() => {
        this.generateMemoryBus()
      })
    },
    // 在进行任何针对 MemoryBus 的修改后，刷新每个子任务的 MemoryBus,保证 MemoryBus 都是重新被获取的
    async generateMemoryBus() {
      try {
        // 获取 taskList
        const taskList = await this.generateTaskList()
        // 刷新 memoryBus
        const result = await this.memoryBus.refresh(taskList)
        // 从 Task1 开始循环，调用解析函数为其分配 MemoryBus
        if (result) {
          Object.keys(taskList).forEach((key) => {
            if (this.$refs['task' + key] && this.$refs['task' + key][0]) {
              // 如果已经选择好了工具，则为其分配 memoryBus
              // 这里优化余地很大，可以考虑传递给 taskEdit 一个统一的 MemoryBus，而不是调用三次 getMemory 方法
              this.$refs['task' + key][0].setFrontMemoryBus(this.memoryBus.getMemory(key, 0))
              this.$refs['task' + key][0].setMemoryBus(this.memoryBus.getMemory(key, 1))
              this.$refs['task' + key][0].setPostMemoryBus(this.memoryBus.getMemory(key, 2))
            }
          })
        }
      } catch (error) {
        console.log(error)
      }
    },
    // 根据设置好的大模型提示词让大模型生成应用名称和描述
    llmRecommended() {
      const data = {
        original_name: '',
        original_description: '',
        instruction: this.appRequirement
      }

      const linkElement = document.querySelector('.llm-link')
      if (linkElement) {
        // 修改文字并禁用点击
        linkElement.textContent = '正在智能推荐应用名称和描述，请稍候…'
        linkElement.href = '#'
        linkElement.style.pointerEvents = 'none'
      }

      generateAppInfo(data)
        .then(res => {
          this.describeAppName = res.name
          this.describeApp = res.description

          if (linkElement) {
            linkElement.textContent = '智能推荐应用名称和描述'
            linkElement.href = '#' // 可以恢复原来的链接地址
            linkElement.style.pointerEvents = 'auto'
          }
        })
        .catch(err => {
          console.log('获取大模型生成的应用信息出错：', err)

          if (linkElement) {
            linkElement.textContent = '智能推荐应用名称和描述'
            linkElement.href = '#'
            linkElement.style.pointerEvents = 'auto'
          }
        })
    }
  }
}
</script>

<style lang="scss" scoped>
.llm-link {
  float: left;
}
.llm-link:hover {
  color: skyblue;
  text-decoration: underline;
}
.waiting-task-list{
  padding-top: 15px;
  padding-bottom: 15px;
  padding-left: 10px;
  background-color: white;
}
.app-requirement{
  margin-bottom: 15px;
  padding-top: 15px;
  padding-bottom: 15px;
  padding-left: 10px;
  background-color: #e5e5e5;
}
.main-create{
  height: 88vh  ;
}
.left-create{
  width: 70%;
}
.right-create{
  width: 30%;
}
.sub-task {
  margin-bottom: 15px;
}
.save-button-container{
  display: flex;
  justify-content: center;
  margin-top: 2cap;
}
.sava-button{
  width: auto;
}
.head-log{
  font-weight: bold;
  font-size: 18px;
}
.input-create{
  position: relative;
  left: 0;
  width: 100%;
  top: 50%
}
/*隐藏el-main的滚动条*/
.hide-scrollbar {
  -ms-overflow-style: none;  /* IE 10+ */
  scrollbar-width: none;  /* Firefox */
}

.hide-scrollbar::-webkit-scrollbar {
  /*display: none;   Safari and Chrome */
  width: auto; /* Chrome, Safari, and Opera */
}

.hide-scrollbar::-webkit-scrollbar-track {
  background: initial; /* Chrome, Safari, and Opera */
}

.hide-scrollbar::-webkit-scrollbar-thumb {
  background: initial; /* Chrome, Safari, and Opera */
}
</style>
